#include <sendrecv.h>
#include "pub_log.h"
#include "md5.h"

/*************************************************************************
 * 函 数 名：  get_file_size
 * 函数功能：  
 *             获取文件实际长度
 *             
 * 参    数：
 *     输  入:
 *             filename  文件名
 *     输  出:
 *		无
 *             
 * 返    回:
 *            0 成功, 非0 失败
 **************************************************************************/
long get_file_size( char *filename )
{
	struct stat f_stat;
	if (filename == NULL)
	{
		return -1;
	}

	if( stat( filename, &f_stat ) == -1 )
	{
		return -1;
	}

	return (long)f_stat.st_size;
}
int sevr_put_file(int sockId, char *fileName)
{
	int iRc = 0, iFileLen;
	char rFileName[FILENAMELEN];
	sfile_t sfile;
	char *pcBuf = (char *)&sfile;

	memset(&sfile, 0x00, sizeof(sfile_t));
	memset(rFileName, 0x00, sizeof(rFileName));

	sprintf(rFileName, "%s%s", SERVERFILEPATH, fileName);
	
	iRc = Compute_file_md5(rFileName, sfile.fileMd5);
        if (iRc < 0)
        {
		slog_err("compute_file_md5 fail! filename = [%s]", rFileName);
		return -1;
        }	
	slog_debug("[file - %s] md5 value = [%s]", rFileName, sfile.fileMd5);
	iFileLen = get_file_size(rFileName);
	slog_info("获取目的文件[%s]大小,filelen=[%d]!", fileName, iFileLen);
	sprintf(sfile.fileLen, "%d", iFileLen);
	sprintf(sfile.fileName, "%s", fileName);
	if( iFileLen < 0 )
	{
		slog_err("获取目的文件[%s]大小错误filelen = [%d]! (error code: %d - %s)", fileName, iFileLen, errno, strerror(errno));

		sprintf(sfile.resCode, "E001");//E001 获取文件长度错误
		iRc = write(sockId, pcBuf, sizeof(sfile_t));
		if(iRc < 0)
		{
			slog_err("write() err! (error code: %d - %s)", errno, strerror(errno));
			return(-1);
		}
		return -1;
	}
	sprintf(sfile.resCode, "E000");//E000 无错误
	iRc = write(sockId, pcBuf, sizeof(sfile_t));
	if(iRc < 0)
	{
		slog_err("write() err! (error code: %d - %s)", errno, strerror(errno));
		return(-1);
	}

	if(file_put(sockId, rFileName, iFileLen) < 0)
	{
		log_err("file_put() err!");
		return -1;
	}

	return 0;
}
int cli_get_file(int sockId)
{
	int iRc = 0, iFileLen;
	sfile_t sfile;
	char *pcBuf = (char *)&sfile;
	char md5_str[MD5_STR_LEN + 1];
	char rFileName[FILENAMELEN];

	memset(&sfile, 0x00, sizeof(sfile_t));

	if(read(sockId, pcBuf, sizeof(sfile_t)) < 0)
	{
		slog_err("read() err! (error code: %d - %s)", errno, strerror(errno));
		return -1;
	}
	slog_info("get sfile.resCode = [%s] sfile.fileLen = [%s] sfile.fileName = [%s] sfile.fileMd5 = [%s]", sfile.resCode, sfile.fileLen, sfile.fileName, sfile.fileMd5);

	if(strcmp(sfile.resCode, "E000")!= 0)
	{
		slog_err("get sfile.resCode != E000 sfile.resCode = [%s]", sfile.resCode);	
		return -1;
	}

	iFileLen = atoi(sfile.fileLen);
	if( iFileLen < 0 )
	{
		slog_err("获取目的文件[%s]大小错误filelen = [%d]!", sfile.fileName, sfile.fileLen);
		return -1;
	}
	if(file_get(sockId, sfile.fileName, iFileLen) < 0)
	{
		log_err("file_gut() err!");
		return -1;
	}
	//MD5校验
	memset(md5_str, 0x00, sizeof(md5_str));
	memset(rFileName, 0x00, sizeof(rFileName));
        sprintf(rFileName, "%s%s", CLIENTFILEPATH, sfile.fileName);
        iRc = Compute_file_md5(rFileName, md5_str);
        if (iRc < 0)
        {
                slog_err("compute_file_md5 fail! filename = [%s]", rFileName);
                return -1;
        }
        slog_debug("[file - %s] md5 value = [%s]" ,rFileName, md5_str);	
	if(strcmp(md5_str, sfile.fileMd5) == 0)
	{
		slog_info("md5 check succ! sfile.fileMd5 = [%s], md5_str = [%s]", sfile.fileMd5, md5_str);
	}
	else
	{
		slog_err("md5 check err! sfile.fileMd5 = [%d], md5_str = [%s]", sfile.fileMd5, md5_str);
		return -1;
	}

	return 0;
}
int file_put(int sockId,char *cfileName,int iFileLen)
{
	int offset;	
	FILE *fp=NULL;
	char pcfileBuf[ONCE_FILE_BLOCK+1];		

	slog_info("开始发送文件，文件大小为[%d]字节,sockId=[%d]", iFileLen, sockId);

	fp = fopen(cfileName,"rb");//二进制形式打开

	if( iFileLen == 0 )
	{
		slog_info("发送完毕，发送文件大小为[%d]字节,sockId=[%d]",iFileLen,sockId);
		fclose(fp);
		fp = NULL;
		return 0;
	}

	fseek(fp,0,SEEK_SET);
	offset=0;
	while(offset<iFileLen)
	{
		fseek(fp,offset,SEEK_SET);	
		memset(pcfileBuf,0x00,ONCE_FILE_BLOCK);

		if(iFileLen-offset>ONCE_FILE_BLOCK)
		{
			fread(pcfileBuf,ONCE_FILE_BLOCK,1,fp);
			offset+=ONCE_FILE_BLOCK;
			if(Sock_send(sockId,pcfileBuf,ONCE_FILE_BLOCK,0)<0)
			{
				slog_err("发送文件过程中出错，已发送[%d]字节,sockId=[%d]",offset,sockId);
				fclose(fp);
				fp = NULL;
				return -1;
			}
		}else
		{
			fread(pcfileBuf,iFileLen-offset,1,fp);			
			if(Sock_send(sockId,pcfileBuf,iFileLen-offset,0)<0)
			{
				slog_err("发送文件过程中出错，已发送[%d]字节,sockId=[%d]",offset,sockId);
				fclose(fp);
				fp = NULL;
				return -1;
			}
			offset+=iFileLen-offset;
		}	
	}	
	fclose(fp);
	fp = NULL;
	if(offset != iFileLen)
	{
		slog_info("发送失败,发送文件大小为[%d]字节,实际文件大小为[%d]字节", offset, iFileLen);
		return -1;
	}
	slog_info("发送完毕，发送文件大小为[%d]字节,sockId=[%d]",offset,sockId);
	return 0;
}
int createDir(const char *sPathName)  
{  
	char   DirName[FILENAMELEN];  
	int    i,len;  

	memset(DirName, 0x00, sizeof(DirName));
	strcpy(DirName,   sPathName);  
	len = strlen(DirName);  
	if(DirName[len-1]!='/')  
	{
		strcat(DirName,   "/");  
	}
	len = strlen(DirName);  

	for(i=1;i<len;i++)  
	{  
		if(DirName[i]=='/')  
		{  
			DirName[i]   =   0;  
			if( access(DirName, F_OK )!=0 )  
			{  
				if(mkdir(DirName, 0755)==-1)  
				{   
					return   -1;   
				}  
			}  
			DirName[i] = '/';  
		}  
	}  

	return   0;  
} 
int file_get(int sockId,char *cfileName,int iFileLen)
{
	int offset;
	FILE *fp=NULL;
	char rFileName[FILENAMELEN];
	char pcfileBuf[ONCE_FILE_BLOCK+1];
	char filePath[FILENAMELEN];
	char *pathPtr = NULL; 

	memset(rFileName, 0x00, sizeof(rFileName));	
	sprintf(rFileName, "%s%s", CLIENTFILEPATH, cfileName);
	memset(filePath, 0x00, sizeof(filePath));	
	sprintf(filePath, "%s%s", CLIENTFILEPATH, cfileName);
	pathPtr = filePath + strlen(filePath) - 1;

	while(pathPtr != filePath)		
	{
		if(*pathPtr == '/')
		{
			*pathPtr = '\0';
			break;
		}
		else
		{
			pathPtr--;
		}
	}
	slog_debug("filePath = [%s]", filePath);
	/*
	   if(*pathPtr == *filePath)
	   {
	   slog_err("获取目录名失败");
	   return -1;	
	   }
	 */

	fp=fopen(rFileName,"wb");
	if(fp == NULL && errno == 2)
	{
		slog_err("fopen() err! filename=[%s] (error code: %d - %s)", rFileName, errno, strerror(errno));	
		createDir(filePath);
		fp=fopen(rFileName,"wb");
		if(fp == NULL)
		{
			slog_err("fopen() err! filename=[%s] (error code: %d - %s)", rFileName, errno, strerror(errno));	
			return -1;
		}
	}
	else if(fp == NULL)
	{
		slog_err("fopen() err! filename=[%s] (error code: %d - %s)", rFileName, errno, strerror(errno));	
		return -1;
	}

	/*接收文件体*/
	slog_info("开始接收文件,文件大小为[%d]字节[%s],sockId=[%d]", iFileLen, rFileName, sockId);

	if( iFileLen == 0 )
	{
		slog_info("接收完毕，接收文件大小为[%d]字节,sockId=[%d]", iFileLen, sockId);
		fclose(fp);
		fp = NULL;
		return 0;
	}

	fseek(fp,0,SEEK_SET);
	offset=0;
	while(offset<iFileLen)
	{
		fseek(fp,offset,SEEK_SET);
		memset(pcfileBuf,0x00,ONCE_FILE_BLOCK);

		if(iFileLen-offset>ONCE_FILE_BLOCK){			
			if(Sock_recv(sockId,pcfileBuf,ONCE_FILE_BLOCK,0)<0)
			{
				fclose(fp);
				fp = NULL;
				slog_err("接收文件过程中出错，已接收[%d]字节,sockId=[%d]", offset, sockId);
				return -1;
			}
			fwrite(pcfileBuf,ONCE_FILE_BLOCK,1,fp);
			offset+=ONCE_FILE_BLOCK;			
		}else{				
			if(Sock_recv(sockId,pcfileBuf,iFileLen-offset,0)<0)
			{
				fclose(fp);
				fp = NULL;
				slog_err("接收文件过程中出错，已接收[%d]字节,sockId=[%d]", offset, sockId);
				return -1;
			}
			fwrite(pcfileBuf,iFileLen-offset,1,fp);
			offset+=iFileLen-offset;
		}	
	}	
	fclose(fp);
	fp = NULL;
	if(offset != iFileLen)
	{
		slog_info("接收失败,接收文件大小为[%d]字节,实际文件大小为[%d]字节", offset, iFileLen);
		return -1;
	}
	slog_info("接收完毕,接收文件大小为[%d]字节,sockId=[%d]",offset,sockId);
	return 0;
}
/**********************************************************************
 *  int Sock_recv                                                      *
 *  功能：接收远端数据                                                 *
 *  参数：iSocketID-远端socket id                                      *
 *  返回值:0/-1/长度                                                   *
 *                                                                     *
 **********************************************************************/ 
int Sock_recv(int iSocketID,char *buf,int length,int timeout){
	/***接收指定长度数据,time,0-短时间,-1长时间,其他传入时间***/
	int  nTotalLen;
	int  nSubLen;
	int  nShouldLen;
	int iRc;
	iRc=nTotalLen=nSubLen=nShouldLen=0;
	nShouldLen=length;
	if(length<=0){
		errno=0;
		if(timeout<0){
			iRc=Sock_waitfor_read(iSocketID,WAITSECONDS);
		}else if(timeout==0){
			iRc=Sock_waitfor_read(iSocketID,-1);
		}else{
			iRc=Sock_waitfor_read(iSocketID,timeout);
		}
		if(iRc<0){
			return(-1);
		}else if(iRc==0){
			/*/超时*/
			return(0);
		}
		nSubLen=recv(iSocketID,buf,1024*80,0);
		if(nSubLen>=0){
			return(nSubLen);
		}else{
			return(-1);
		}
	}
	while(nTotalLen<nShouldLen){	
		if(timeout<=0){
			iRc=Sock_waitfor_read(iSocketID,WAITSECONDS);
		}else{
			iRc=Sock_waitfor_read(iSocketID,timeout);
		}
		if(iRc<=0){
			return(-1);
		}
		nSubLen=recv(iSocketID,buf+nTotalLen,nShouldLen-nTotalLen,0);
		if(nSubLen<=0){
			if(nTotalLen>0){
				return(0);
			}else{
				return(-1);
			}
		}
		nTotalLen+=nSubLen;
	}
	return (nTotalLen);
}

/**********************************************************************
 *  int Sock_send                                                        *
 *  功能：发送数据                                                     *
 *  参数：iSocketID-远端socket id                                      *
 *  返回值:0/-1                                                        *
 *                                                                     *
 **********************************************************************/ 
int Sock_send(int iSocketID,char *buf,int length,int timeout){
	/*/time:0短时间,-1长时间,其他传入时间*/
	int  nTotalLen;
	int  nSubLen;
	int  nShouldLen;
	int iRc;
	iRc=nTotalLen=nSubLen=nShouldLen=0;
	nShouldLen=length;
	while(nTotalLen<nShouldLen){	
		if(timeout<0){
			iRc=Sock_waitfor_write(iSocketID,WAITSECONDS);
		}else if(timeout==0){
			iRc=Sock_waitfor_write(iSocketID,-1);
		}else{
			iRc=Sock_waitfor_write(iSocketID,timeout);
		}
		if(iRc<=0){
			return(-1);
		}
		nSubLen=send(iSocketID,buf+nTotalLen,nShouldLen-nTotalLen,0);
		if(nSubLen<=0){
			return(-1);
		}
		nTotalLen+=nSubLen;
	}
	return(0);
}
int Sock_waitfor_write(int iSocketID,int waitseconds){
	fd_set    rmask;
	struct    timeval time_out,*ptr;
	int iRc;
	FD_ZERO(&rmask);
	FD_SET((unsigned int)iSocketID,&rmask);
	if(waitseconds>=0){
		time_out.tv_sec  = waitseconds ;
		time_out.tv_usec = 0;
	}else{
		time_out.tv_sec  = 0 ;
		time_out.tv_usec = 200000;
	}
	ptr = &time_out;
	iRc=0;
	/*循环等待，直到socket空闲可写*/
	while(1){
		iRc = select(iSocketID+1,0,&rmask,0,ptr);
		if(iRc>0){
			break;
		}else if(iRc==0){
			/*超时*/
			break;
		}else{
			if(errno==EINTR)
				continue;
			else
				break;
		}
	}
	return iRc;
}
int Sock_waitfor_read(int iSocketID,int waitseconds){
	fd_set    rmask;
	struct    timeval time_out,*ptr;
	int iRc;
	FD_ZERO(&rmask);
	FD_SET((unsigned int)iSocketID,&rmask);
	if(waitseconds>=0){
		time_out.tv_sec  = waitseconds ;
		time_out.tv_usec = 0;
	}else{
		time_out.tv_sec  = 0 ;
		time_out.tv_usec = 200000;
	}
	ptr = &time_out;
	iRc=0;
	/*循环等待，直到socket空闲可读*/
	while(1){
		iRc = select(iSocketID+1,&rmask,0,0,ptr);
		if(iRc>0){
			break;
		}else if(iRc==0){
			/*超时*/
			break;
		}else{
			if(errno==EINTR)
				continue;
			else
				break;
		}
	}
	return iRc;
}
